Subclassing Built-In Types Is Tricky


In [5]:
class DoppelDict(dict):
    def __setitem__(self, key, value):
        super().__setitem__(key, [value] * 2)

In [6]:
dd = DoppelDict(one=1)

In [7]:
dd


Out[7]:
{'one': 1}

In [8]:
dd['two'] = 2

In [9]:
dd


Out[9]:
{'one': 1, 'two': [2, 2]}

In [10]:
dd.update(three=3)

In [11]:
dd


Out[11]:
{'one': 1, 'three': 3, 'two': [2, 2]}

In [12]:
class AnswerDict(dict):
    def __getitem__(self, key):
        return 42

In [13]:
ad = AnswerDict(a='foo')
ad['a']


Out[13]:
42

In [14]:
d = {}
d.update(ad)
d['a']


Out[14]:
'foo'

In [15]:
d


Out[15]:
{'a': 'foo'}

In [16]:
import collections

In [17]:
class DoppelDict2(collections.UserDict):
    def __setitem__(self, key, value):
        super().__setitem__(key, [value] * 2)

In [18]:
dd = DoppelDict2(one=1)
dd


Out[18]:
{'one': [1, 1]}

In [19]:
dd['two'] = 2
dd


Out[19]:
{'two': [2, 2], 'one': [1, 1]}

In [20]:
dd.update(three=3)
dd


Out[20]:
{'three': [3, 3], 'two': [2, 2], 'one': [1, 1]}

In [21]:
class AnswerDict2(collections.UserDict):
    def __getitem__(self, key):
        return 42

In [22]:
ad = AnswerDict2(a='foo')
ad['a']


Out[22]:
42

In [23]:
d = {}
d.update(ad)
d['a']


Out[23]:
42

In [24]:
d


Out[24]:
{'a': 42}

Multiple Inheritance and Method Resolution Order


In [25]:
class A:
    def ping(self):
        print('ping', self)

In [26]:
class B(A):
    def pong(self):
        print('pong:', self)

In [27]:
class C(A):
    def pong(self):
        print('PONG:', self)

In [39]:
class D(B, C):
    
    def ping(self):
        super().ping()
        print('post-ping:', self)
        
    def pingpong(self):
        self.ping()
        super().ping()
        self.pong()
        super().pong()
        C.pong(self)

In [40]:
d = D()
d.pong()


pong: <__main__.D object at 0x000000AD5FC89B00>

In [41]:
C.pong(d)


PONG: <__main__.D object at 0x000000AD5FC89B00>

In [42]:
D.__mro__


Out[42]:
(__main__.D, __main__.B, __main__.C, __main__.A, object)

In [43]:
d.ping()


ping <__main__.D object at 0x000000AD5FC89B00>
post-ping: <__main__.D object at 0x000000AD5FC89B00>

In [44]:
d.pingpong()


ping <__main__.D object at 0x000000AD5FC89B00>
post-ping: <__main__.D object at 0x000000AD5FC89B00>
ping <__main__.D object at 0x000000AD5FC89B00>
pong: <__main__.D object at 0x000000AD5FC89B00>
pong: <__main__.D object at 0x000000AD5FC89B00>
PONG: <__main__.D object at 0x000000AD5FC89B00>

In [45]:
bool.__mro__


Out[45]:
(bool, int, object)

In [46]:
def print_mro(cls):
    print(', '.join(c.__name__ for c in cls.__mro__))

In [47]:
print_mro(bool)


bool, int, object

In [48]:
import numbers
print_mro(numbers.Integral)


Integral, Rational, Real, Complex, Number, object

In [49]:
import io
print_mro(io.BytesIO)


BytesIO, _BufferedIOBase, _IOBase, object

In [50]:
print_mro(io.TextIOWrapper)


TextIOWrapper, _TextIOBase, _IOBase, object

In [51]:
import tkinter
print_mro(tkinter.Text)


Text, Widget, BaseWidget, Misc, Pack, Place, Grid, XView, YView, object

Multiple Inheritance in the Real World


In [52]:
import tkinter

In [53]:
print_mro(tkinter.Toplevel)


Toplevel, BaseWidget, Misc, Wm, object

In [54]:
print_mro(tkinter.Widget)


Widget, BaseWidget, Misc, Pack, Place, Grid, object

In [55]:
print_mro(tkinter.Button)


Button, Widget, BaseWidget, Misc, Pack, Place, Grid, object

In [56]:
print_mro(tkinter.Entry)


Entry, Widget, BaseWidget, Misc, Pack, Place, Grid, XView, object

In [57]:
print_mro(tkinter.Text)


Text, Widget, BaseWidget, Misc, Pack, Place, Grid, XView, YView, object

In [ ]: